
#include <cstdlib>
#include <sstream>
#include <list>

/// ----------------------------------------
///
///  Declaració operacions tipus CUA
///
/// ----------------------------------------

template <class T>
class cua : private std::list<T> {

 public: 
   /// constructora, permet declarar variables de 
   /// tipus cua<T>, inicialitzades a una cua buida.
   cua();
   /// destructora, coses del C++
   ~cua();

   /// operacio C&x == cua resultant d'encuar x en C
   cua<T> operator&(const T&) const;
   /// obtenir el primer element de la cua
   const T& primer() const;
   /// obtenir la resta d'elements (els que estan per darrera el primer)
   cua<T> resta() const;    
   /// consultar si una cua es buida o no
   bool es_buida() const;

   /// afegir un element a una cua
   void encuar(const T&);
   /// avançar la cua (eliminar el primer element)
   void avancar();

   /// per poder fer prints
   template <class U> friend std::ostream& operator<<(std::ostream&, const cua<U>&);
};





/// ============================================== ///
///             Definició operacions               ///

// constructora
template <class T>
cua<T>::cua() {};

// destuctora
template <class T>
cua<T>::~cua() {};

/// operador afegir element
template <class T>
cua<T> cua<T>::operator&(const T& x) const {
  cua<T> b=(*this);
  b.push_back(x);
  return b;
}

// obtenir l'element primer de la cua
template <class T>
const T& cua<T>::primer() const {
  if (this->empty()) {
    std::cout<<"ERROR - Operació 'primer' sobre una cua buida."<<std::endl;
    exit(1);
  }
  return this->front();
}

// obtenir la resta d'elements, els que estan per darrera el primer.
template <class T>
cua<T> cua<T>::resta() const {
  if (this->empty()) {
    std::cout<<"ERROR - Operacio 'resta' sobre una cua buida."<<std::endl;
    exit(1);
  }
  cua<T> q=(*this);
  q.pop_front();
  return q;
}

// consultar si una cua es buida o no
template <class T>
bool cua<T>::es_buida() const {
  return this->empty();
}

// afegir un element a una cua
template <class T>
void cua<T>::encuar(const T &x) {
  this->push_back(x);
}

// fer avancar la cua, eliminant el primer
template <class T>
void cua<T>::avancar() {
  this->pop_front();
}


/// ============================================== ///
///           Definició operacions friend          ///

/// operador << d'escriptura
template <class U>
std::ostream& operator<<(std::ostream& os , const cua<U>& x) {
  os<<">";
  for (typename std::list<U>::const_reverse_iterator p=x.rbegin(); p!=x.rend(); p++) {
    if (p!=x.rbegin()) os<<"|";
    os<<(*p);
  }
  os<<">";
  return os;
}

